/***************************************************************************************************
 *
 * Project: Examples
 *
 * Class: LessonTree
 *
 * File name: LessonTreePanel.java
 *
 * Aug 21, 2007
 *
 **************************************************************************************************/

package com.eastmountain.chinese.lessontree;

import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.Collections;
import java.util.Observable;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.ToolTipManager;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;

import com.eastmountain.chinese.db.flashcards.records.Lesson;
import com.eastmountain.chinese.gui.controllers.ToolBarButtons;
import com.eastmountain.chinese.observable.HZFlashcardsDataModel;

/*******************************************************************************
 * 
 * Class: LessonTreePanel
 * 
 * Note:  This class is instantiated by FlashcardsMenuBar
 *        which uses the lesson numbers obtained from
 *        this class to populate the flash cards in
 *        HanZiDisplayPanel.
 * 
 ******************************************************************************/

@SuppressWarnings("serial")
public class LessonTreePanel implements TreeSelectionListener {

    private HZFlashcardsDataModel hzFlashcardsDataModel;

    private static JDialog dialog;

    // lessonNumbers contains the array of lesson numbers
    // returned by showDialog()

    private int[] lessonNumbers = null;

    private JTree tree;

    private ButtonPanel buttonPanel;
    
    /***************************************************************************
     * 
     * LessonTreePanel
     * 
     **************************************************************************/

    public LessonTreePanel() {

        hzFlashcardsDataModel = HZFlashcardsDataModel.getInstance();

        buildDialog();

        MouseListener ml = new TreeMouseListener();

        tree.addMouseListener(ml);

    }

    /***************************************************************************
     * 
     * buildDialog
     * 
     **************************************************************************/

    public void buildDialog() {

        dialog = new JDialog((Frame) null, "Lesson Selector", true);

        // Create the buttons

        buttonPanel = new ButtonPanel(this);
        
        tree = constructTree();

        // Create the scroll pane and add the tree to it.

        JScrollPane treeView = new JScrollPane( tree, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED );

        Container pane = dialog.getContentPane();
        pane.removeAll();

        JPanel panel = new JPanel();
        //panel.setLayout(new GridLayout(2,0));
        pane.setLayout(new BoxLayout( pane, BoxLayout.Y_AXIS ) );

        pane.add(treeView);
        pane.add(buttonPanel);
        
        //pane.add( panel );

        dialog.pack();

        //
        // Set event handlers
        //

        dialog.addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent evt) {

                dialog.setVisible(false);
                dialog.dispose();
            }
        });

        dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

    }

    /***************************************************************************
     * 
     * showDialog
     * 
     **************************************************************************/

    public int[] showDialog() {

        if (dialog == null) {

            buildDialog();

        }

        dialog.toFront();
        dialog.setVisible(true);

        // TODO account for cancel

        return getLessonNumbers();

    }

    /***************************************************************************
     * 
     * constructTree
     * 
     **************************************************************************/

    public JTree constructTree() {

        JTree tree;
        ImageIcon lessonWorkingSetlIcon;

        DefaultMutableTreeNode top
            = new DefaultMutableTreeNode( hzFlashcardsDataModel.getTreeName() );

        // Create the nodes.

        createNodes(top);

        // Create a tree that allows multiple selections

        // TODO Perhaps resize depending on how many lessons may be visible

        tree = new JTree(top);
        tree.setPreferredSize(new Dimension(200, 300));
        tree.getSelectionModel().setSelectionMode(TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION);
        
        lessonWorkingSetlIcon = ToolBarButtons.SHUFFLE.buttonIcon();
        
        tree.setCellRenderer(new LessonTreeCellRenderer( lessonWorkingSetlIcon ));
        
       //Enable tool tips.
        
        ToolTipManager.sharedInstance().registerComponent(tree);

        // Listen for when the selection changes.

        tree.addTreeSelectionListener(this);

        return tree;

    }

    /***********************************************************************
     * 
     * finishOpenLessons
     * 
     **********************************************************************/

	public void finishOpenLessons() {
		
		int[] lessonNumbers = getSelectedLessonNumbers();
		setLessonNumbers(lessonNumbers);

		getDialog().setVisible(false);
		getDialog().dispose();
		
	}
    
    /***************************************************************************
     * 
     * clearTreeNodes
     * 
     **************************************************************************/

    public void clearTreeNodes() {

        tree.clearSelection();

    }

    /***************************************************************************
     * 
     * getSelectedLessonNumbers
     * 
     **************************************************************************/

    public int[] getSelectedLessonNumbers() {

        Vector<Lesson> lessons = null;
        int[] lessonNumbers = null;
        int noSelected;

        lessons = getSelectedNodes();

        if (!(lessons == null)) {

            // JTree returns the selected lessons in the order
            // they were selected, not in lesson order

            Collections.sort(lessons);

            noSelected = lessons.size();
            lessonNumbers = new int[noSelected];

            for (int i = 0; i < lessonNumbers.length; i++) {

                lessonNumbers[i] = lessons.elementAt(i).getLessonNumber();

            }

            // TODO maybe offer two different orderings

        }

        return lessonNumbers;

    }

    /***************************************************************************
     * 
     * getSelectedNodes
     * 
     **************************************************************************/

    protected Vector<Lesson> getSelectedNodes() {

        System.out.println("*****  getSelectedNodes() entered  ******");

        TreePath[] treePaths = null;
        Vector<Lesson> selectedLessons = null;
        boolean selected = false;
        treePaths = tree.getSelectionPaths();

        if (!(treePaths == null)) {

            selectedLessons = new Vector<Lesson>();

            System.out.println( "\nLessonTreePanel selected paths\n" );

            for (TreePath element : treePaths) {

                System.out.println( "????????? TreePath: " + element.toString() );

                DefaultMutableTreeNode node = (DefaultMutableTreeNode) element
                                                .getLastPathComponent();

                if (node.getUserObject() instanceof Lesson) {

                    Lesson lesson = getSelectedLessonNode(node);

                    selected = true;

                    // Lesson lesson = (Lesson) node.getUserObject();
                    selectedLessons.add(lesson);

                    System.out.println("Lesson: " + lesson.getTitle());

                }

                // }

            }

        }

        if (!selected) {

        }

        return selectedLessons;

    }

    /***************************************************************************
     * 
     * getSelectedLessonNodes
     * 
     **************************************************************************/

    protected Lesson getSelectedLessonNode(DefaultMutableTreeNode node) {

        System.out.println("*****  getSelectedLessonNodes() entered  ******");

        Lesson lesson = null;

        if (node.getUserObject() instanceof Lesson) {

            lesson = (Lesson) node.getUserObject();

            System.out.println("Lesson: " + lesson.getTitle());

        }

        return lesson;

    }

    /***************************************************************************
     * 
     * createNodes
     * 
     **************************************************************************/

    private void createNodes(DefaultMutableTreeNode top) {

        for (String[] element : hzFlashcardsDataModel.getLessonLevelNames() ) {

            addLessonsToTree(top, element[0], element[1]);

        }

    }

    /***************************************************************************
     * 
     * displayNodeInfo
     * 
     **************************************************************************/

    public void displayNodeInfo() {
        
        int rowCount;
        TreePath treePath;
        
        rowCount = tree.getRowCount(); 

        System.out.println( "\nDisplay for: " + rowCount + " rows");
        
        for ( int i = 0; i < rowCount; i++ ) {
           
            treePath = tree.getPathForRow( i );
            
            Object[] objects = treePath.getPath();
            
            for ( int i1 = 0; i1 < objects.length; i1++ ) {

                System.out.println( "Object: " + i1 + " - " + objects[i1].getClass().getName() );    

            }
            
            System.out.println( "TreePath: " + treePath.toString() );
            
        }
        
        System.out.println();

    }

    /***************************************************************************
     * 
     * addLessonsToTree
     * 
     **************************************************************************/

    private void addLessonsToTree(DefaultMutableTreeNode top, String lessonLevel,
                                    String lessonLevelName) {

        DefaultMutableTreeNode lessonLevelNode;
        DefaultMutableTreeNode lessonNode;

        LevelName levelName;

        Vector<Lesson> lessons = new Vector<Lesson>();

        lessons = hzFlashcardsDataModel.getLessonsForLevel( lessonLevel );

        levelName = new LevelName(lessonLevelName);

        lessonLevelNode = new DefaultMutableTreeNode(levelName);
        top.add(lessonLevelNode);

        for ( Lesson lesson : lessons ) {

            lessonNode = new DefaultMutableTreeNode(lesson);
            lessonLevelNode.add(lessonNode);

        }

    }

    /***************************************************************************
     * 
     * valueChanged
     * 
     **************************************************************************/

    public void valueChanged(TreeSelectionEvent treeSelectionEvent) {

        System.out.println("*****  valueChanged() entered  ******");

        System.out
                                        .println("\n    Event source: "
                                                                        + treeSelectionEvent
                                                                                                        .getSource()
                                                                                                        .getClass()
                                                                                                        .getSimpleName());

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();

        if (node == null) {

            return;

        }

        Object userObject = node.getUserObject();

        if (userObject instanceof LevelName) {

            // TODO open children

            String lessonDescription = ((LevelName) userObject).getLevelName();

            System.out.println("\n    *****  Level clicked  - " + lessonDescription + "  ******");

        } else if (userObject instanceof Lesson) {

            Lesson lesson = (Lesson) userObject;

            System.out.println("\n    *****  Lesson clicked - " + lesson.toString() + "  ******");

        } else {

            System.out.println("\n    *****  Something unexpected clicked - a "
                                            + userObject.getClass().getSimpleName() + "  ******");

        }

    }

    /***************************************************************************
     * 
     * createImageIcon
     * 
     **************************************************************************/
    
    protected static ImageIcon createImageIcon(String path) {
        
        java.net.URL imgURL = LessonTreePanel.class.getResource(path);
        
        if (imgURL != null) {
            
            return new ImageIcon(imgURL);
          
        } else {
            
            System.err.println("! ! ! ! Couldn't find file: " + path);
            return null;
            
        }
    }
    
    /***************************************************************************
     * 
     * getLessonNumbers
     * 
     **************************************************************************/

    public int[] getLessonNumbers() {

        return lessonNumbers;

    }

    /***************************************************************************
     * 
     * setLessonNumbers
     * 
     **************************************************************************/

    public void setLessonNumbers(int[] lessonNumbers) {

        this.lessonNumbers = lessonNumbers;

    }

    /***************************************************************************
     * 
     * getTree - used by Test Case TestLessonTreePanel
     * 
     **************************************************************************/
   
    public JTree getTree() {
    	
    	return( tree );
    	
    }

    /***************************************************************************
     * 
     * getButtonPanel - used by Test Case TestLessonTreePanel
     * 
     **************************************************************************/

    public ButtonPanel getButtonPanel() {

        return buttonPanel;

    }

    /***************************************************************************
     * 
     * getDialog
     * 
     **************************************************************************/

    public JDialog getDialog() {

        return dialog;

    }

    /***************************************************************************
     * 
     * update
     * 
     **************************************************************************/

    public void update(Observable obj, Object arg) {

        // System.out.println( "!!! LessonTreePanel.update() invoked !!!!" );
        // System.out.println( "Class name: " + arg.getClass().getSimpleName()
        // );

    }

    /***************************************************************************
     * 
     * Class: TreeMouseListener
     * 
     **************************************************************************/

    public final class TreeMouseListener extends MouseAdapter {

        /***********************************************************************
         * 
         * mousePressed
         * 
         **********************************************************************/

        @Override
        public void mousePressed(MouseEvent e) {

            System.out.println("******  mousePressed() entered");

            int selectedRow = tree.getRowForLocation(e.getX(), e.getY());

            TreePath selectedPath = tree.getPathForLocation(e.getX(), e.getY());

            if (selectedRow != -1) {

                if (e.getClickCount() == 1) {

                    // Do nothing special

                } else if (e.getClickCount() == 2) {

                    doubleClick(selectedPath);

                }

            }

        }

        /***********************************************************************
         * 
         * doubleClick
         * 
         **********************************************************************/

        private void doubleClick(TreePath treePath) {

            System.out.println("******  doubleClick() entered");

            DefaultMutableTreeNode node = (DefaultMutableTreeNode) treePath.getLastPathComponent();

            System.out.println("        Object clicked: "
                               + node.getUserObject().getClass().getSimpleName());

            Object userObject = node.getUserObject();

            if (userObject instanceof LevelName) {

                String lessonDescription = ((LevelName) node.getUserObject()).getLevelName();

                System.out.println("\n    *****  Level clicked  - " + lessonDescription
                                                + "  ******");

            } else {

                Lesson lesson = (Lesson) node.getUserObject();

                System.out.println("        Lesson:       " + lesson.getTitle()
                		           + " number: " + lesson.getLessonNumber());

                //int[] lessonNumbers = getSelectedLessonNumbers();
                //setLessonNumbers(lessonNumbers);

                finishOpenLessons();

            }

        }

    }

}

/*******************************************************************************
 * 
 * Class: LessonTreeCellRenderer
 * 
 ******************************************************************************/

@SuppressWarnings("serial")
class LessonTreeCellRenderer extends DefaultTreeCellRenderer {
    
    private ImageIcon imageIcon;

    public LessonTreeCellRenderer( ImageIcon imageIcon ) {
        
        this.imageIcon = imageIcon;

    }

    /***************************************************************************
     * 
     * getTreeCellRendererComponent
     * 
     **************************************************************************/

    @Override
    public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel,
                                    boolean expanded, boolean leaf, int row, boolean hasFocus) {

        super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, hasFocus);

        // TODO add icon to indicate lesson is active

        if ( leaf ) {
            
            setIcon( imageIcon );
           
        }

        String description = getLessonDescription(value);
        setText( description );

        return this;

    }

    /***************************************************************************
     * 
     * getLessonDescription
     * 
     **************************************************************************/

    public String getLessonDescription(Object value) {

        String lessonDescription;

        DefaultMutableTreeNode node = (DefaultMutableTreeNode) value;

        if (node.getUserObject() instanceof LevelName) {

            lessonDescription = ((LevelName) node.getUserObject()).getLevelName();

        } else if (node.getUserObject() instanceof Lesson) {

            Lesson lesson = (Lesson) node.getUserObject();
            lessonDescription = lesson.getLessonNumber() + " - " + lesson.getTitle();

        } else if (node.getUserObject() instanceof String) {

            lessonDescription = (String) node.getUserObject();

        } else {

            System.out.println("Node class: " + node.getUserObject().getClass().getSimpleName());
            lessonDescription = "?????";

        }

        return lessonDescription;

    }

}

/*******************************************************************************
 * 
 * Class: ButtonPanel
 * 
 ******************************************************************************/

@SuppressWarnings("serial")
class ButtonPanel extends JPanel implements ActionListener {

    private LessonTreePanel lessonTreePanel;

    // private HZFlashcardsDataModel hzFlashcardsDataModel = null;

    private JButton openButton;

    private JButton clearButton;

    private static String OPEN = "Open";

    private static String CLEAR = "Clear";

    /***************************************************************************
     * 
     * ButtonPanel
     * 
     **************************************************************************/

    public ButtonPanel( LessonTreePanel lessonTreePanel ) {

        this.lessonTreePanel = lessonTreePanel;

        // hzFlashcardsDataModel = HZFlashcardsDataModel.getInstance();

        openButton = new JButton(ButtonPanel.OPEN);
        openButton.setActionCommand(ButtonPanel.OPEN);
        openButton.addActionListener(this);

        openButton.requestFocusInWindow();

        clearButton = new JButton(ButtonPanel.CLEAR);
        clearButton.setActionCommand(ButtonPanel.CLEAR);
        clearButton.addActionListener(this);

        add(openButton);
        add(clearButton);

    }

    /***************************************************************************
     * 
     * actionPerformed
     * 
     **************************************************************************/

    public void actionPerformed(ActionEvent event) {

        if (ButtonPanel.OPEN.equals(event.getActionCommand())) {

            System.out.println("+====+ " + ButtonPanel.OPEN);
            
            //lessonTreePanel.displayNodeInfo();

            lessonTreePanel.finishOpenLessons();

        } else if (ButtonPanel.CLEAR.equals(event.getActionCommand())) {

            System.out.println("+====+ " + ButtonPanel.CLEAR);

            lessonTreePanel.clearTreeNodes();

        }

    }

    public JButton getOpenButton() {

        return openButton;
    }

}
